﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace System.Controls.Command
{
  public class DelegateCommand : ICommand
  {
    private readonly Action fAction;

    private readonly Func<bool> fFunc;

    public DelegateCommand() { }

    public DelegateCommand( Action execAction, Func<bool> canExecFunc = null )
    {
      fAction = execAction;
      fFunc = canExecFunc;
    }

    public virtual void Execute()
    {
      if ( fAction != null )
        fAction.Invoke();
    }

    public virtual bool CanExecute()
    {
      return ( fFunc == null || fFunc() ) && InternalCommandManager.IsCommandEnabled;
    }

    #region Implementation of ICommand

    void ICommand.Execute( object parameter )
    {
      Execute();
    }

    bool ICommand.CanExecute( object parameter )
    {
      return CanExecute();
    }

    public event EventHandler CanExecuteChanged
    {
      add { CommandManager.RequerySuggested += value; }
      remove { CommandManager.RequerySuggested -= value; }
    }

    #endregion
  }

  public class DelegateCommand<T> : ICommand
  {
    private readonly Action<T> fAction;

    private readonly Func<T, bool> fFunc;

    public DelegateCommand() { }

    public DelegateCommand( Action<T> execAction, Func<T, bool> canExecFunc = null )
    {
      fAction = execAction;
      fFunc = canExecFunc;
    }

    public virtual void Execute( T parameter )
    {
      if ( fAction != null )
        fAction.Invoke( parameter );
    }

    public virtual bool CanExecute( T parameter )
    {
      return ( fFunc == null || fFunc( parameter ) ) && InternalCommandManager.IsCommandEnabled;
    }

    #region Implementation of ICommand

    void ICommand.Execute( object parameter )
    {
      if ( parameter == null )
      {
        Execute( default( T ) );
        return;
      }

      if ( parameter is T )
        Execute( (T) parameter );
    }

    bool ICommand.CanExecute( object parameter )
    {
      if ( parameter == null )
        return CanExecute( default( T ) );

      if ( parameter is T )
        return CanExecute( (T) parameter );

      return false;
    }

    public event EventHandler CanExecuteChanged
    {
      add { CommandManager.RequerySuggested += value; }
      remove { CommandManager.RequerySuggested -= value; }
    }

    #endregion
  }
}
